<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./vue.js"></script>
    <!-- <script src="./axios.js"></script> -->
</head>

<body>
    <div id="app">
        <base-input v-on:focus.native="onFocus"></base-input>
    </div>

    <script>
        //
        /*
            将原生事件绑定到组件

            你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。
            这时，你可以使用 v-on 的 .native 修饰符：

            <base-input v-on:focus.native="onFocus"></base-input>

            在有的时候这是很有用的，不过在你尝试监听一个类似 <input> 的非常特定的元素时，这并不是个好主意。
            比如上述 <base-input> 组件可能做了如下重构，所以根元素实际上是一个 <label> 元素：

            <label>
                {{ label }}
                <input
                v-bind="$attrs"
                v-bind:value="value"
                v-on:input="$emit('input', $event.target.value)"
                >
            </label>

            这时，父级的 .native 监听器将静默失败。
            它不会产生任何报错，但是 onFocus 处理函数不会如你预期地被调用。

            为了解决这个问题，Vue 提供了一个 $listeners 属性，它是一个对象，
            里面包含了作用在这个组件上的所有监听器。

            例如：

            {
            focus: function (event) {...}
            input: function(value) {...},
            }

            有了这个 $listeners 属性， 你就可以配合 v - on = "$listeners"
            将所有的事件监听器指向这个组件的某个特定的子元素。 
            对于类似 < input > 的你希望它也可以配合 v - model 工作的组件来说，
        */

        //虽然不知道以下代码到底实现了什么
        //但总觉得很重要！！！！
        Vue.component('base-input', {
            inheritAttrs: false,
            props: ['label', 'value'],
            computed: {
                inputListeners: function() {
                    let vm = this
                        //Object.assign() 将所有对象合并成一个新的对象
                    return Object.assign({},
                        //我们从父级添加所有监听器
                        this.$listeners,
                        //我们添加自定义监听器
                        //或者覆写监听器行为
                        {
                            //这里确保组件配合 V-model 工作
                            input: function(event) {
                                vm.$emit('input', event.target.value)
                            }
                        }
                    )
                }
            },
            template: `
                <label>
                    {{label}}
                    <input v-bind="$attrs" v-bind:value="value" v-on="inputListeners"/>
                </label>
            `
        });

        new Vue({
            el: app
        })
    </script>
</body>

</html>